using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using OnePiece.Core.Exception;
using OnePiece.Core.Extension.Paging;
using OnePiece.Core.ModelComponent;
using OnePiece.Core.RepositoryComponent;
using System.Linq;

namespace OnePiece.Core.BusinessComponent
{
    public abstract class BusinessComponentBase<TModel, IRepositoryComponent>
        where TModel : ModelComponentBase
        where IRepositoryComponent : IRepositoryComponentBase<TModel>
    {

        #region Constructor
        public BusinessComponentBase()
        {
            LoadUnitySetting();
            DefaultRepository = this.UnityContainer.Resolve<IRepositoryComponent>();
        }

        public BusinessComponentBase(IRepositoryComponent repositoryComponent)
        {
            DefaultRepository = repositoryComponent;
        }

        #endregion

        #region Properties
        public IRepositoryComponent DefaultRepository { get; set; }
        #endregion

        #region Add/Update/Delete Entity

        public virtual void Save(TModel entity)
        {
            int recordsAffected;
            if (entity.IsDeleted)
            {
                recordsAffected = this.Delete(entity.EntityId);
            }
            else
            {
                if (entity.IsNew)
                {
                    entity.EntityId = this.GenerateId(entity);
                    recordsAffected = this.Insert(entity);
                }
                else
                {
                    recordsAffected = this.Update(entity);
                }
            }

            if (recordsAffected == 0)
            {
                throw new NoRecordsAffectedException();
            }
            
        }

        public virtual void Save(IList<TModel> entities)
        {
            foreach (var entity in entities)
            {
                this.Save(entity);
            }
        }
         

        #endregion

        #region GetEntity
        public virtual TModel GetById(Guid? entityId)
        {            
            return DefaultRepository.GetById(entityId);
        }
        public virtual TModel GetById(string entityId)
        {

            return DefaultRepository.GetById(new Guid(entityId));
        }

        #endregion

        #region GetEntityList
        public virtual IList<TModel> GetByCriteriaWithSelector(Func<TModel, bool> predicate, Func<TModel, TModel> selectSelector)
        {
            return DefaultRepository.GetByCriteriaWithSelector(predicate, selectSelector);
        }

        public virtual IList<TModel> GetAll()
        {
            return DefaultRepository.GetAll();
        }

        public virtual IList<TModel> GetAllPerPage(ref PageExtensionHelper pager)
        {
            return DefaultRepository.GetAllPerPage(ref pager);
        }

        public virtual IList<TModel> GetAllByCriteria(Func<TModel, bool> predicate)
        {
            return DefaultRepository.GetAllByCriteria(predicate);
        }

        public virtual IList<TModel> GetAllByCriteriaPerPage(Func<TModel, bool> predicate, ref PageExtensionHelper pager)
        {
            return DefaultRepository.GetAllByCriteriaPerPage(predicate, ref pager);
        }

        #endregion

        #region CheckBusinessRule
        internal virtual void CheckBusinessRuleBeforeDelete(string entityId)
        {
            //TODO: Check the validtion rule
            //Implement the enterprise library validation here

        }

        internal virtual void CheckBusinessRuleBeforeUpdate(TModel entity)
        {
            //Check the entity Data.Annotations Validaton
            //Implement the enterprise library validation here
        }

        internal virtual void CheckBusinessRuleBeforeInsert(TModel entity)
        {
            //Check the entity Data.Annotations Validaton
            //Implement the enterprise library validation here
        }


        #endregion

        #region Unity Container
        public UnityContainer UnityContainer { get; set; }

        internal void LoadUnitySetting()
        {
            //read the unity setting from the web.config
            UnityContainer = new UnityContainer();
            var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers["DataComponentContainer"].Configure(UnityContainer);

        }

        #endregion

        #region Helpers
        internal Guid GenerateId(TModel entity)
        {
            return (entity.EntityId == Guid.Empty) ? Guid.NewGuid() : entity.EntityId;            
        }

        internal virtual int Update(TModel entity)
        {
            CheckBusinessRuleBeforeUpdate(entity);
            return DefaultRepository.Update(entity);
        }

        internal virtual int Insert(TModel entity)
        {
            CheckBusinessRuleBeforeInsert(entity);
            return DefaultRepository.Insert(entity);
        }

        internal virtual int Delete(Guid entityId)
        {
            CheckBusinessRuleBeforeDelete(entityId.ToString());
            return DefaultRepository.Delete(entityId);
        }

        #region Multiple Delete
        private void Delete(IEnumerable<Guid> entityIds)
        {
            foreach (var id in entityIds)
                this.Delete(id);
        }

        private void Delete(string delimitedId, char[] delimiter)
        {
            var ids = delimitedId.Split(delimiter);
            //cast as Guid
            var entityIds = new List<Guid>(ids.Count());
            foreach (var s in ids)
                entityIds.Add(new Guid(s.Trim()));

            this.Delete(entityIds);
        }

        private void Delete(string delimitedId)
        {
            Delete(delimitedId, new[] { ',' });
        } 
        #endregion

        #endregion
    }
}